package main

import (
	"fmt"
	"math/big"
	"strconv"
	"strings"
)

// Parser represents the syntax analyzer
type Parser struct {
	tokens []*Token
	pos    int
}

// NewParser creates a new parser
func NewParser(tokens []*Token) *Parser {
	return &Parser{
		tokens: tokens,
		pos:    0,
	}
}

// current returns the current token
func (p *Parser) current() *Token {
	if p.pos < len(p.tokens) {
		return p.tokens[p.pos]
	}
	return &Token{Type: TokenEOF}
}

// advance moves to the next token
func (p *Parser) advance() {
	if p.pos < len(p.tokens)-1 {
		p.pos++
	}
}

// Parse parses tokens into an AST
func (p *Parser) Parse() (*Value, error) {
	return p.parseExpression()
}

// parseExpression parses a single expression
func (p *Parser) parseExpression() (*Value, error) {
	token := p.current()

	switch token.Type {
	case TokenNumber:
		return p.parseNumber()
	case TokenString:
		return p.parseString()
	case TokenBoolean:
		return p.parseBoolean()
	case TokenChar:
		return p.parseChar()
	case TokenSymbol:
		return p.parseSymbol()
	case TokenQuote:
		return p.parseQuote()
	case TokenLeftParen:
		return p.parseList()
	case TokenVector:
		return p.parseVector()
	case TokenEOF:
		return nil, fmt.Errorf("unexpected end of input")
	default:
		return nil, fmt.Errorf("unexpected token: %s", token.Value)
	}
}

// parseNumber parses a number token into appropriate numerical type
func (p *Parser) parseNumber() (*Value, error) {
	token := p.current()
	p.advance()

	// Parse exactness prefix
	exact := true // Default to exact for integers and rationals
	numStr := token.Value

	if strings.HasPrefix(numStr, "#e") {
		exact = true
		numStr = numStr[2:] // Remove #e prefix
	} else if strings.HasPrefix(numStr, "#i") {
		exact = false
		numStr = numStr[2:] // Remove #i prefix
	}

	// Check for complex number (contains 'i' at the end)
	if strings.HasSuffix(numStr, "i") {
		return p.parseComplex(numStr, exact)
	}

	// Check for rational number (contains /)
	if strings.Contains(numStr, "/") {
		return p.parseRational(numStr, exact)
	}

	// Check for decimal point or scientific notation
	if strings.Contains(numStr, ".") || strings.Contains(numStr, "e") || strings.Contains(numStr, "E") {
		// For real numbers with decimal points or scientific notation,
		// default to inexact unless explicitly marked as exact with #e
		if !strings.HasPrefix(token.Value, "#e") {
			exact = false
		}
		return p.parseReal(numStr, exact)
	}

	// Must be an integer
	return p.parseInteger(numStr, exact)
}

// parseInteger parses an integer string
func (p *Parser) parseInteger(numStr string, exact bool) (*Value, error) {
	if val, err := strconv.ParseInt(numStr, 10, 64); err == nil {
		if exact {
			return NewInteger(val), nil
		} else {
			return NewInexactReal(float64(val)), nil
		}
	}

	// Try parsing as big integer for very large numbers
	bigInt := new(big.Int)
	if _, ok := bigInt.SetString(numStr, 10); ok {
		if exact {
			return NewIntegerBig(bigInt), nil
		} else {
			// Convert to float
			f, _ := new(big.Float).SetInt(bigInt).Float64()
			return NewInexactReal(f), nil
		}
	}

	return nil, fmt.Errorf("invalid integer: %s", numStr)
}

// parseRational parses a rational number (fraction)
func (p *Parser) parseRational(numStr string, exact bool) (*Value, error) {
	parts := strings.Split(numStr, "/")
	if len(parts) != 2 {
		return nil, fmt.Errorf("invalid rational: %s", numStr)
	}

	numerator, err1 := strconv.ParseInt(parts[0], 10, 64)
	denominator, err2 := strconv.ParseInt(parts[1], 10, 64)

	if err1 == nil && err2 == nil {
		if denominator == 0 {
			return nil, fmt.Errorf("division by zero in rational: %s", numStr)
		}
		if exact {
			return NewRational(numerator, denominator), nil
		} else {
			return NewInexactReal(float64(numerator) / float64(denominator)), nil
		}
	}

	// Try with big integers
	numBig := new(big.Int)
	denBig := new(big.Int)
	_, ok1 := numBig.SetString(parts[0], 10)
	_, ok2 := denBig.SetString(parts[1], 10)

	if ok1 && ok2 {
		if denBig.Sign() == 0 {
			return nil, fmt.Errorf("division by zero in rational: %s", numStr)
		}
		rat := new(big.Rat).SetFrac(numBig, denBig)
		if exact {
			return NewRationalBig(rat), nil
		} else {
			f, _ := new(big.Float).SetRat(rat).Float64()
			return NewInexactReal(f), nil
		}
	}

	return nil, fmt.Errorf("invalid rational: %s", numStr)
}

// parseReal parses a real number (decimal or scientific notation)
func (p *Parser) parseReal(numStr string, exact bool) (*Value, error) {
	if val, err := strconv.ParseFloat(numStr, 64); err == nil {
		if exact {
			return NewExactReal(val), nil
		} else {
			return NewInexactReal(val), nil
		}
	}

	return nil, fmt.Errorf("invalid real: %s", numStr)
}

// parseComplex parses a complex number
func (p *Parser) parseComplex(numStr string, exact bool) (*Value, error) {
	// Remove the trailing 'i'
	numStr = strings.TrimSuffix(numStr, "i")

	// Handle pure imaginary numbers: "i", "+i", "-i"
	if numStr == "" || numStr == "+" {
		// "i" or "+i" => 0+1i
		return NewComplex(complex(0, 1), exact), nil
	} else if numStr == "-" {
		// "-i" => 0-1i
		return NewComplex(complex(0, -1), exact), nil
	}

	// Check for rectangular form: a+bi or a-bi
	// Find the last + or - that's not at the beginning
	lastSignPos := -1
	for i := len(numStr) - 1; i > 0; i-- {
		if numStr[i] == '+' || numStr[i] == '-' {
			lastSignPos = i
			break
		}
	}

	if lastSignPos > 0 {
		// Rectangular form: real+imag or real-imag
		realStr := numStr[:lastSignPos]
		imagStr := numStr[lastSignPos:]

		// Parse real part
		realPart, err := strconv.ParseFloat(realStr, 64)
		if err != nil {
			return nil, fmt.Errorf("invalid real part in complex: %s", realStr)
		}

		// Parse imaginary part
		var imagPart float64
		if imagStr == "+" {
			imagPart = 1
		} else if imagStr == "-" {
			imagPart = -1
		} else {
			var err error
			imagPart, err = strconv.ParseFloat(imagStr, 64)
			if err != nil {
				return nil, fmt.Errorf("invalid imaginary part in complex: %s", imagStr)
			}
		}

		return NewComplex(complex(realPart, imagPart), exact), nil
	} else {
		// Pure imaginary number: 5i, -3i, etc.
		imagPart, err := strconv.ParseFloat(numStr, 64)
		if err != nil {
			return nil, fmt.Errorf("invalid imaginary number: %s", numStr)
		}
		return NewComplex(complex(0, imagPart), exact), nil
	}
}

// parseString parses a string token
func (p *Parser) parseString() (*Value, error) {
	token := p.current()
	p.advance()
	return NewString(token.Value), nil
}

// parseBoolean parses a boolean token
func (p *Parser) parseBoolean() (*Value, error) {
	token := p.current()
	p.advance()

	if token.Value == "#t" {
		return NewBoolean(true), nil
	} else if token.Value == "#f" {
		return NewBoolean(false), nil
	}

	return nil, fmt.Errorf("invalid boolean: %s", token.Value)
}

// parseChar parses a character token
func (p *Parser) parseChar() (*Value, error) {
	token := p.current()
	p.advance()

	// Parse character literal: #\c or #\name
	charStr := token.Value
	if !strings.HasPrefix(charStr, "#\\") {
		return nil, fmt.Errorf("invalid character literal: %s", charStr)
	}

	charPart := charStr[2:] // Remove #\\ prefix

	// Handle named characters
	switch charPart {
	case "space":
		return NewChar(' '), nil
	case "tab":
		return NewChar('\t'), nil
	case "newline":
		return NewChar('\n'), nil
	case "return":
		return NewChar('\r'), nil
	default:
		// Single character
		if len(charPart) == 1 {
			return NewChar(rune(charPart[0])), nil
		}
		return nil, fmt.Errorf("invalid character name: %s", charPart)
	}
}

// parseSymbol parses a symbol token
func (p *Parser) parseSymbol() (*Value, error) {
	token := p.current()
	p.advance()
	return NewSymbol(token.Value), nil
}

// parseQuote parses a quoted expression
func (p *Parser) parseQuote() (*Value, error) {
	p.advance() // skip quote
	expr, err := p.parseExpression()
	if err != nil {
		return nil, err
	}

	// Return (quote expr)
	return NewList([]*Value{NewSymbol("quote"), expr}), nil
}

// parseVector parses a vector literal
func (p *Parser) parseVector() (*Value, error) {
	token := p.current()
	p.advance() // consume vector token

	// Extract the content between #( and )
	content := token.Value[2 : len(token.Value)-1]

	// Tokenize the content
	subtokens, err := Tokenize(content)
	if err != nil {
		return nil, fmt.Errorf("error tokenizing vector content: %w", err)
	}

	// Create a new parser for the subtokens
	subparser := NewParser(subtokens)

	// Parse all expressions in the vector
	var elements []*Value
	for subparser.current().Type != TokenEOF {
		elem, err := subparser.parseExpression()
		if err != nil {
			return nil, fmt.Errorf("error parsing vector element: %w", err)
		}
		elements = append(elements, elem)
	}

	// Create a new vector value
	return NewVector(elements), nil
}

// parseList parses a list expression
func (p *Parser) parseList() (*Value, error) {
	p.advance() // skip '('

	var elements []*Value

	for p.current().Type != TokenRightParen && p.current().Type != TokenEOF {
		expr, err := p.parseExpression()
		if err != nil {
			return nil, err
		}
		elements = append(elements, expr)

		// Check for dotted pair syntax
		if p.current().Type == TokenDot {
			p.advance() // skip '.'
			// Parse the cdr expression
			cdrExpr, err := p.parseExpression()
			if err != nil {
				return nil, err
			}
			// Check for closing paren
			if p.current().Type != TokenRightParen {
				return nil, fmt.Errorf("expected ')' after dotted pair")
			}
			p.advance() // skip ')'
			// Create nested pairs
			if len(elements) == 1 {
				// Simple dotted pair: (a . b)
				return NewPair(elements[0], cdrExpr), nil
			} else {
				// Multiple elements before dot: (a b . c)
				// Build from right to left
				result := cdrExpr
				for i := len(elements) - 1; i >= 0; i-- {
					result = NewPair(elements[i], result)
				}
				return result, nil
			}
		}
	}

	if p.current().Type != TokenRightParen {
		return nil, fmt.Errorf("expected ')'")
	}

	p.advance() // skip ')'

	// For regular lists (no dot), use TypeList
	return NewList(elements), nil
}

// ParseString parses a string input into an AST
func ParseString(input string) (*Value, error) {
	tokens, err := Tokenize(input)
	if err != nil {
		return nil, err
	}

	parser := NewParser(tokens)
	return parser.Parse()
}
